#include "resource.h"
#include "system.h"
#include "list.h"
#include "xml.h"
#include "script.h"

#include <string.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>

typedef struct _UFO_TextureNode
{
	char *id;
	UFO_Texture texture;
}UFO_TextureNode;

typedef struct _UFO_ImageNode
{
	char *id;
	IMAGE	*image;
}UFO_ImageNode;

typedef struct _UFO_FontNode
{
	char *id;
	UFO_Font font;
}UFO_FontNode;

/*typedef struct _UFO_ScriptNode
{
	char *id;
	const char *script;
}UFO_ScriptNode;*/

typedef struct _UFO_Resource_Internal
{
	UFO_List textureList;
	UFO_List fontList;
	UFO_List imageList;
	//UFO_List scriptList;

	UFO_Handle handle;
}UFO_UFO_Resource_Internal, *PUFO_UFO_Resource_Internal;

UFO_Resource g_resource;

UFO_Resource ufoResourceGetDefault()
{
	return g_resource;
}

UFO_Resource ufoResourceAddFromXML(const char *filename)
{	
	xmlDocPtr doc = 0;			
	xmlNodePtr curNode = 0;	

	doc = ufoXmlDocFromFile(filename);
	if (!doc)
		return 0;

	curNode = xmlDocGetRootElement(doc);

	if (!curNode || xmlStrcmp(curNode->name, (const xmlChar*)"UFO") != 0) {
		return 0;
	}

	curNode = curNode->children;
	
	while (curNode) {//### seek to Resource
		if (xmlStrcmp(curNode->name, (const xmlChar*)"Resource") == 0)
			break;
		curNode = curNode->next;
	}

	if (curNode) {

		if (!g_resource) {
			PUFO_UFO_Resource_Internal pRes = malloc(sizeof(UFO_UFO_Resource_Internal));
			memset(pRes, 0, sizeof(UFO_UFO_Resource_Internal));		
			pRes->handle = ufoCreateHandle(UFO_ID_RESOURCE, pRes);
			g_resource = (UFO_Resource)pRes->handle;
		}

		curNode = curNode->children;
		while (curNode) {
			
			if (xmlStrcmp(curNode->name, (const xmlChar*)"Image") == 0) {
				
				char path[300] = {0};
				IMAGE *image = malloc(sizeof(IMAGE));
				
				xmlChar *file = xmlGetProp(curNode, (const xmlChar*)"file");
				xmlChar *id = xmlGetProp(curNode, (const xmlChar*)"id");

				memset(image, 0, sizeof(IMAGE));
				strcpy(path, ufoGetResPath());
				strcat(path, (const char*)file);
				
				if (ufoImageFromFile(path, 0, image)) {
					ufoResourceAddImage(image, (char*)id);
					if (file)
						xmlFree(file);
				}
				else {
					if (file)
						xmlFree(file);
					if (id)
						xmlFree(id);
				}
			}
			else if (xmlStrcmp(curNode->name, (const xmlChar*)"Font") == 0) {
				xmlChar *id = xmlGetProp(curNode, (const xmlChar*)"id");
				xmlChar *facename = xmlGetProp(curNode, (const xmlChar*)"facename");
				xmlChar *size = xmlGetProp(curNode, (const xmlChar*)"size");
                xmlChar *bold = xmlGetProp(curNode, (const xmlChar*)"bold");
				int nSize = 0;
                int nBold = 0;
				UFO_Font font = 0;

				if (size) {
					sscanf((const char*)size, "%d", &nSize);
					xmlFree(size);
				}
                
				if (bold) {
					if (strcmp(bold, "true") == 0) {
                        nBold = 1;
                    }
					xmlFree(bold);
				}

				font = ufoFontCreate(facename, nSize, nBold);

				if (facename) {
					xmlFree(facename);
				}

				ufoResourceAddFont(font, id);
			}
			else if (xmlStrcmp(curNode->name, (const xmlChar*)"Script") == 0) {
				xmlChar *id = xmlGetProp(curNode, (const xmlChar*)"id");
				xmlChar *filename = xmlGetProp(curNode, (const xmlChar*)"file");

				if (filename) {
					UFO_IO file = 0;
					char path[300] = {0};
					strcpy(path, ufoGetResPath());
					strcat(path, (const char*)filename);
					file = ufoIoFromFile(path);
					if (file) {
						int nSize = ufoIoGetSize(file);
						unsigned char *script = malloc(nSize+1);
						script[nSize] = 0;
						ufoIoRead(file, script, nSize);
						//ufoResourceAddScript(id, script);
						ufoScriptAdd(id, script);
						ufoIoClose(file);
					}
					
					xmlFree(filename);
				}
			}
			else if (xmlStrcmp(curNode->name, (const xmlChar*)"Texture") == 0) {
				
				xmlChar *id = xmlGetProp(curNode, (const xmlChar*)"id");
				xmlChar *image = xmlGetProp(curNode, (const xmlChar*)"image");
				xmlChar *srcRect = xmlGetProp(curNode, (const xmlChar*)"srcRect");
				xmlChar *drawMode = xmlGetProp(curNode, (const xmlChar*)"drawMode");
				xmlChar *girdRect = xmlGetProp(curNode, (const xmlChar*)"girdRect");
				xmlChar *destRect = xmlGetProp(curNode, (const xmlChar*)"destRect");

				IMAGE* pImage = ufoResourceGetImage((const char*)image);
				if (pImage){

					UFO_Texture tex = 0;
					ufoRect rectSrc = {0, 0, pImage->width, pImage->height};
					if (srcRect)
						sscanf((const char*)srcRect, "%f, %f, %f, %f",
							&rectSrc.left, &rectSrc.top, &rectSrc.right, &rectSrc.bottom);
					
					tex = ufoTextureCreate(pImage, &rectSrc);

					if (drawMode) {
						if (xmlStrcmp(drawMode, (const xmlChar*)"9Gird") == 0 && girdRect) {
							
							TEXTUREMODE drawMode = {TEXTUREMODE_9GRID, 0, 0, 0, 0};
							sscanf((const char*)girdRect, "%f, %f, %f, %f",
								&drawMode.rect.left, &drawMode.rect.top, &drawMode.rect.right, &drawMode.rect.bottom);

							if (destRect) {
								sscanf((const char*)destRect, "%f, %f, %f, %f",
									&drawMode.destRect.left, &drawMode.destRect.top, &drawMode.destRect.right, &drawMode.destRect.bottom);
							}

							ufoTextureSetMode(tex, &drawMode);
						}
						else if (xmlStrcmp(drawMode, (const xmlChar*)"Stretch") == 0) {
							//### default drawMode, do nothing
						}
						else if (xmlStrcmp(drawMode, (const xmlChar*)"Center") == 0) {
							TEXTUREMODE drawMode = {TEXTUREMODE_CENTER, 0, 0, 0, 0};
							if (destRect) {
								sscanf((const char*)destRect, "%f, %f, %f, %f",
									&drawMode.destRect.left, &drawMode.destRect.top, &drawMode.destRect.right, &drawMode.destRect.bottom);
							}
							ufoTextureSetMode(tex, &drawMode);
						}						
					}

					ufoResourceAddTexture(tex, (char*)id);
				}
                
                if (image)
                    xmlFree(image);
                if (srcRect)
                    xmlFree(srcRect);
                if (drawMode)
                    xmlFree(drawMode);
                if (girdRect)
                    xmlFree(girdRect);
				if (destRect)
					xmlFree(destRect);
			}

			curNode = curNode->next;
		}

		return g_resource;
	}

	return 0;
}

int ufoResourceAddTexture(UFO_Texture texture, char *id)
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes) {
		UFO_TextureNode node = {id, texture};

		if (!pRes->textureList) {
			pRes->textureList = ufoListCreate(sizeof(UFO_TextureNode));
		}

		return ufoListPushBack(pRes->textureList, &node);
	}
	return 0;
}

UFO_Texture ufoResourceGetTexture(const char *id)
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes && pRes->textureList) {
		UFO_List_Iteartor it = ufoListBegin(pRes->textureList);
		while (it) {
			UFO_TextureNode *node = ufoListGetElement(it);
			if (node && strcmp(node->id, id)==0 ) {
				return node->texture;
			}
			it = ufoListIteartorForward(it);
		}
	}
	return 0;
}

IMAGE* ufoResourceGetImage(const char *id)
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes && pRes->imageList) {
		UFO_List_Iteartor it = ufoListBegin(pRes->imageList);
		while (it) {
			UFO_ImageNode *node = ufoListGetElement(it);
			if (node && strcmp(node->id, id)==0 ) {
				return node->image;
			}
			it = ufoListIteartorForward(it);
		}
	}
	return 0;
}

int ufoResourceAddImage(IMAGE *image, char *id)
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes) {
		UFO_ImageNode node = {id, image};

		if (!pRes->imageList) {
			pRes->imageList = ufoListCreate(sizeof(UFO_ImageNode));
		}

		return ufoListPushBack(pRes->imageList, &node);
	}
	return 0;
}

UFO_Font ufoResourceGetFont( const char *id )
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes && pRes->fontList) {
		UFO_List_Iteartor it = ufoListBegin(pRes->fontList);
		while (it) {
			UFO_FontNode *node = ufoListGetElement(it);
			if (node && strcmp(node->id, id)==0 ) {
				return node->font;
			}
			it = ufoListIteartorForward(it);
		}
	}
	return 0;
}

int ufoResourceAddFont( UFO_Font font, char *id )
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes) {
		UFO_FontNode node = {id, font};
		
		if (!pRes->fontList) {
			pRes->fontList = ufoListCreate(sizeof(UFO_FontNode));
		}

		return ufoListPushBack(pRes->fontList, &node);
	}
	return 0;
}

/*int ufoResourceAddScript(char *id, const char* script)
{
	PUFO_UFO_Resource_Internal pRes = ufoObjectFromHandle((UFO_Handle)g_resource);
	if (pRes) {
		UFO_ScriptNode node = {id, script};

		if (!pRes->scriptList) {
			pRes->scriptList = ufoListCreate(sizeof(UFO_ScriptNode));
		}

		return ufoListPushBack(pRes->scriptList, &node);
	}
	return 0;
}*/